package com.example.httpclient.controller;

import com.example.httpclient.handler.CustomHttpClientResponseHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.auth.AuthCache;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

/**
 * @author zpMeng
 * @since 9/4/2024
 */
@Slf4j
@RestController
@RequestMapping("httpClient")
public class SecurityController {

    @Value("${spring.security.user.name}")
    private String user;
    @Value("${spring.security.user.password}")
    private String password;

    private final HttpHost targetHost = new HttpHost("http", "10.86.0.155", 8080);


    @GetMapping("/security")
    public String testSecurity() {
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        log.info("{}", authentication);
        Object principal = authentication.getPrincipal();
        log.info("{}", principal);
        return "request url with security succeed";
    }

    @GetMapping("authProgress")
    public void authProgress() throws IOException {
        final HttpGet request = new HttpGet("http://10.86.0.155:8080/httpClient/security");
        try (CloseableHttpClient client = HttpClientBuilder.create()
                .setDefaultCredentialsProvider(provider())
                .build();

             CloseableHttpResponse response = (CloseableHttpResponse) client
                     .execute(request, new CustomHttpClientResponseHandler())) {

            log.info("{}", response.getCode());
        }
    }

    private BasicCredentialsProvider provider() {
        final BasicCredentialsProvider provider = new BasicCredentialsProvider();
        AuthScope authScope = new AuthScope(targetHost);
        provider.setCredentials(authScope, new UsernamePasswordCredentials(user, password.toCharArray()));
        return provider;
    }

    @GetMapping("preemptive")
    public int preemptive() throws IOException {
        BasicCredentialsProvider provider = provider();

        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();
        BasicScheme basicAuth = new BasicScheme();
        basicAuth.initPreemptive(new UsernamePasswordCredentials(user, password.toCharArray()));
        authCache.put(targetHost, basicAuth);

        // Create context and set auth cache
        HttpClientContext context = HttpClientContext.create();
        context.setAuthCache(authCache);
        context.setCredentialsProvider(provider);

        // Create HttpClient instance with credentials provider
        try (CloseableHttpClient httpClient = HttpClients.custom()
                .build()) {

            // Create the request (example: GET request)
            HttpGet request = new HttpGet("http://10.86.0.155:8080/httpClient/security");

            // Execute the request with context
            CloseableHttpResponse response = (CloseableHttpResponse) httpClient
                    .execute(request, context, new CustomHttpClientResponseHandler());

            return response.getCode();
        }
    }

}